/*
 * Licensed this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.boapi.math;

/**
 * <span lang='en'>Mathfunctions</span>
 * <span lang='de'>Mathematikfunktionen</span>
 * @author Sebastian Ritter
 * @version 2.0.0.0
 */
public class Mathfunctions {
	
	/**
	 * <span lang='en'>Calculate the digits sum of number.</span>
	 * <span lang='de'>Berechnet die Quersumme eines numerischen Wertes</span>
     * @param number
     * @return sum of digits
	 */
    public static final long sumOfDigits (long number) {
      long quersumme = 0;
      if (java.lang.Math.abs(number) > 9) {
        do {
          quersumme += number % 10;
          number = number / 10;
        } while (number > 0);
      }
      else {
        quersumme = number;
      }
      return quersumme;
    }

    /**
     * <span lang='de'>
     * Berechnet die Quersumme eines numerischen Wertes
     * </span>
     * @param number
     * @return Quersumme
     */
    public static final int sumOfDigits (final int number) {
      return java.lang.Math.abs(number) > 9 ? (int) sumOfDigits ((long)number) : number;
    }

    /**
     * <span lang='de'>
     * Luhn-Algorithmus berechnet, ob der �bergebene numerische Wert an der letzten Stelle
     * dem Luhn-Algorithmus entspricht.
     * </span>
     * @param number
     * @return Luhn-Algorithmus erf�llt
     */
    public static final boolean isLuhn (final String number) {
      /* Von rechts beginnend wird jede zweite Ziffer verdoppelt.
       * Sofern das Produkt gr��er als 9 ist wird die Quersumme gebildet
       * Anschlie�end werden werden alle Ziffern addiert
       * Wenn die Summe durch 10 ohne Rest teilbar ist, ist die Nummer korrekt
       */
      int luhnSumme = 0;
      boolean doppeln = false;
      for (int i = number.length() - 1; i >= 0; i--) {
        luhnSumme += Mathfunctions.sumOfDigits (doppeln ? Integer.parseInt(number.substring(i, i+1))*2 : Integer.parseInt(number.substring(i, i+1)));
        doppeln = !doppeln;
      }
      return luhnSumme % 10 == 0;
    }

    /**
     * <span lang='en'>
     * Multiply two int[] and return a new int []. If one array has more elements, these
     * elements are multiply with 1. The length of new array are same as length of array
     * with more elements.<br>
     * <i>It can be used to calculate the weight of digits from number with given factors.</i>
     * <p><strong>Example:</strong><br> 
     * a = {1,2,1,2,1,2,1,2,1}<br>
     * b = {4,5,3,2,6,2,4,3,3}<br>
     * multiply = {4,10,3,4,6,4,4,6,3}<br>
     * </p>
     * </span>
     * <span lang='de'>
     * Multipliziert zwei int[] und liefert ein neues int[] zurück. Sofern ein Array länger ist,
     * werden die überzähligen Elemente mit dem Faktor 1 multipliziert. Die Länge des neuen
     * Arrays entspricht somit stets der Länge des längeren übergebenen Array<br>
     * <i>Die Funktion eignet sich um die Gewichtung der Ziffern einer Nummer mit den entsprechenden
     * Faktoren zu berechnen.</i>
     * <p><strong>Beispiel:</strong><br> 
     * a = {1,2,1,2,1,2,1,2,1}<br>
     * b = {4,5,3,2,6,2,4,3,3}<br>
     * multiply = {4,10,3,4,6,4,4,6,3}<br>
     * </p>
     * </span>
     * @param a an int []
     * @param b an int []
     * @return product int []
     * @since 2.0.0.0
     */
    public static int[] multiply (final int [] a, final int [] b) {
    	int result [] = new int [a.length < b.length ? b.length : a.length];
		int i = 0;
    	if (a.length < b.length) {
    		for (;i < a.length;i++) {
    			result [i] = a[i] * b[i];
    		}
    		do {
    			result[i]=b[i];
    		}
    		while (i<b.length);
    	}
    	else {
    		for (;i<b.length;i++) {
    			result [i] = a[i] * b[i];
    		}
    		while (i<a.length) {
    			result[i] =a[i];
    		}
    	}
    	return result;
    }
    
    /**
     * <span lang='en'>
     * Return the sum of numbers in the array beginning with first index ending with last index.
     * <p><strong>Example:</strong><br> 
     * numbers = {1,2,3,4,5,6,7,8,9}<br>
     * firstIndex = 2<br>
     * lastIndex = 5<br>
     * sumOfNumbers = 3+4+5+6 = 18<br>
     * </p>
     * </span>
     * @param numbers
     * @return sum
     * @since 2.0.0.0
     */
    public static int sumOfNumbers (final int [] numbers, int firstIndex, int lastIndex) {
    	if (firstIndex < 0) {
    		firstIndex = 0;
    	}
    	if (lastIndex > numbers.length -1) {
    		lastIndex = numbers.length -1;
    	}
    	int retValue = 0;
    	for (;firstIndex <= lastIndex; firstIndex++) {
    		retValue += numbers[firstIndex];
    	}
    	return retValue;
    }

    /**
     * <span lang='en'>
     * Return the sum of numbers in the full array.
     * </span>
     * <p><strong>Example:</strong><br> 
     * numbers = {1,2,3,4,5,6,7,8,9}<br>
     * sumOfNumbers = 1+2+3+4+5+6+7+8+9 = 45<br>
     * </p>
     * @param numbers
     * @return sum
     * @since 2.0.0.0
     */
    public static int sumOfNumbers (final int [] numbers) {
    	return sumOfNumbers(numbers,0,numbers.length -1);
    }

    /**
     * <span lang='en'>
     * Return the sum of digits for all given numbers at same index.
     * </span>
     * <p><strong>Example:</strong><br> 
     * numbers = {14,23,35}<br>
     * sumOfDigits = {5,5,8}<br>
     * </p>
     * @param numbers
     * @return sum of digits
     * @since 2.0.0.0
     */
    public static int[] sumOfDigits (final int [] numbers) {
    	int [] retValue = new int [numbers.length];
    	for (int i = 0; i < retValue.length; i++) {
    		retValue[i] = sumOfDigits(numbers[i]);
    	}
    	return retValue;
    }
}

